﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CustomAuthorizationDemo.Authentication;
using CustomAuthorizationDemo.Authorization;
using CustomAuthorizationDemo.Security.Session;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.Filters;
using CustomAuthorizationDemo.DI;

namespace CustomAuthorizationDemo
{
    public class Startup
    {

        private static readonly string swaggerDocName = "v1";
        private readonly string corsPolicyName = "CorsPolicy";
        private readonly IConfiguration Configuration;
        private readonly IHostingEnvironment HostingEnvironment;

        public Startup(IConfiguration configuration, IHostingEnvironment env)
        {
            Configuration = configuration;
            HostingEnvironment = env;
            //using (var serviceScope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
            //{
            //    var env = serviceScope.ServiceProvider.GetRequiredService<IHostingEnvironment>();
            //    var webRoot = env.WebRootPath;
            //}//end using scope
        }


        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddHttpContextAccessor(); //ASP.NET Core 2.2之后的版本，必须添加此代码才能注入IHttpContextAccessor实例
            //添加依赖注入
            services.AddSingleton<IClaimsSession, ClaimsSession>();
            services.AddTransient<IAuthenticationService, SampleAuthenticationService>();
            services.AddSingleton<IPermissionChecker, SamplePermissionChecker>();
            //为控制器和Filter类添加属性注入功能
            services.AddPropertiesAutowiredControllerActivator(this);
            services.AddPropertiesAutowiredFilterProvider();
            //添加身份验证
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = BearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = BearerDefaults.AuthenticationScheme;
            }).AddBearer();

            //跨域
            services.AddCors(options =>
            {
                // CorsPolicy 是自訂的 Policy 名稱
                options.AddPolicy(corsPolicyName, policy =>
                {
                    policy.AllowAnyOrigin()
                          //.AllowCredentials()
                          .AllowAnyHeader()
                          .AllowAnyMethod();
                });
            });
            //Swagger支持
            services.AddSwaggerGen(options =>
            {
                var info = new OpenApiInfo
                {
                    Version = Configuration.GetSection("SwaggerDoc:Version").Value,
                    Title = Configuration.GetSection("SwaggerDoc:Title").Value,
                    Description = Configuration.GetSection("SwaggerDoc:Description").Value,
                };
                //读取appsettings.json文件中的联系人信息
                string contactName = Configuration.GetSection("SwaggerDoc:ContactName").Value;
                string contactNameEmail = Configuration.GetSection("SwaggerDoc:ContactEmail").Value;
                string s = Configuration.GetSection("SwaggerDoc:ContactUrl").Value;
                Uri contactUrl = string.IsNullOrEmpty(s) ? null : new Uri(s);
                if (!string.IsNullOrEmpty(contactName))
                    info.Contact = new OpenApiContact { Name = contactName, Email = contactNameEmail, Url = contactUrl };
                //info.License = new OpenApiLicense { Name = contactName, Url = contactUrl }
                options.SwaggerDoc(swaggerDocName, info);

                var xmlPath = Path.Combine(HostingEnvironment.ContentRootPath, "Api.xml");
                if (File.Exists(xmlPath))
                    options.IncludeXmlComments(xmlPath);
                //options.DocumentFilter<HiddenApiFilter>(); // 在接口类、方法标记属性 [HiddenApi]，可以阻止【Swagger文档】生成
                //options.OperationFilter<AddHeaderOperationFilter>("correlationId", "Correlation Id for the request", false); // adds any string you like to the request headers - in this case, a correlation id
                options.OperationFilter<AddResponseHeadersFilter>();
                options.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();

                options.OperationFilter<SecurityRequirementsOperationFilter>();
                var security = new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
                        },
                        new[] { "readAccess", "writeAccess" }
                    }
                };
                options.AddSecurityRequirement(security);//添加一个必须的全局安全信息，和AddSecurityDefinition方法指定的方案名称要一致，这里是Bearer。
                //给api添加token令牌证书
                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}（注意两者之间是一个空格）\"",
                    Name = "Authorization",//jwt默认的参数名称
                    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.ApiKey
                });
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            //应用身份验证
            app.UseAuthentication();

            //跨域
            app.UseCors(corsPolicyName);

#if NETCOREAPP3_1
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                //endpoints.MapControllers();
                endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
            });
#else
            app.UseMvcWithDefaultRoute();
#endif

            app.UseStaticFiles();

            //Swagger
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint(
                    // url: 需配合 SwaggerDoc 的 name。 "/swagger/{SwaggerDoc name}/swagger.json"
                    url: $"../swagger/{swaggerDocName}/swagger.json", //这里一定要使用相对路径，不然网站发布到子目录时将报告："Not Found /swagger/v1/swagger.json"
                                                                      // description: 用於 Swagger UI 右上角選擇不同版本的 SwaggerDocument 顯示名稱使用。
                    name: "RESTful API v1.0.0"
                );
                //c.InjectOnCompleteJavaScript();
            });
        }
    }
}
